package cn.weekimwee.firstlineofcodeforkotlin.unit10.download

import android.os.AsyncTask
import android.os.Environment
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.File
import java.io.InputStream
import java.io.RandomAccessFile
import java.lang.Exception

/**
 * Created by Wee Kim Wee on 2018/4/8.
 */
class DownloadTask : AsyncTask<String, Int, Int>() {

    var onProgress: ((Int) -> Unit)? = null
    var onSuccess: (() -> Unit)? = null
    var onFailed: (() -> Unit)? = null
    var onPaused: (() -> Unit)? = null
    var onCanceled: (() -> Unit)? = null

    val TYPE_SUCCESS = 0
    val TYPE_FAILED = 1
    val TYPE_PAUSED = 2
    val TYPE_CANCELED = 3

    var isCanceled = false
    var isPaused = false
    var lastProgress = 0

    //执行 参数类型对应 类名后第一个泛型参数
    override fun doInBackground(vararg params: String?): Int {
        var inputStream: InputStream? = null
        var savedFile: RandomAccessFile? = null
        var file: File? = null
        try {
            var downloadedLength = 0L
            val downloadUrl = params[0]
            val fileName = downloadUrl?.substring(downloadUrl.lastIndexOf("/"))
            val directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path
            file = File(directory + fileName)
            if (file.exists()) {
                downloadedLength = file.length()
            }
            val contentLength: Long = getContentLength(downloadUrl)
            if (contentLength == 0L) {
                return TYPE_FAILED
            } else if (contentLength == downloadedLength) {
                return TYPE_SUCCESS
            }
            val client = OkHttpClient()
            val request = Request.Builder()
                    .addHeader("RANGE", "bytes=$downloadedLength-")
                    .url(downloadUrl)
                    .build()
            val response = client.newCall(request).execute()
            if (response != null) {
                inputStream = response.body()?.byteStream()
                savedFile = RandomAccessFile(file, "rw")
                savedFile.seek(downloadedLength)
                val b = byteArrayOf(1024.toByte())
                var total = 0
                var len: Int
                inputStream?.read(b)?.let {
                    len = it
                    while (len != -1) {
                        when {
                            isCanceled -> return TYPE_CANCELED
                            isPaused -> return TYPE_PAUSED
                            else -> {
                                total += len
                                savedFile.write(b, 0, len)
                                val progress = (total + downloadedLength) * 100 / contentLength
                                publishProgress(progress.toInt())
                            }
                        }
                        len = inputStream.read(b)
                    }
                    response.body()?.close()
                    return TYPE_SUCCESS
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            try {
                inputStream?.close()
                savedFile?.close()
                file?.let {
                    if (isCanceled) {
                        file.delete()
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
        return TYPE_FAILED
    }


    //更新 调用publishProgress时执行这个方法   参数类型对应类名后第二个泛型参数
    override fun onProgressUpdate(vararg values: Int?) {
        val progress = values[0]
        if(progress!=null&&progress>lastProgress){
            onProgress?.invoke(progress)
            lastProgress = progress
        }
    }

    //执行完毕时调用   参数类型对应类名后第三个泛型参数  参数就是doInBackground返回的结果
    override fun onPostExecute(result: Int?) {
        when(result){
            TYPE_SUCCESS -> onSuccess?.invoke()
            TYPE_FAILED -> onFailed?.invoke()
            TYPE_PAUSED -> onPaused?.invoke()
            TYPE_CANCELED -> onCanceled?.invoke()
        }
    }

    private fun getContentLength(downloadUrl: String?): Long {
        val okHttpClient = OkHttpClient()
        val request = Request.Builder()
                .url(downloadUrl)
                .build()
        val response = okHttpClient.newCall(request).execute()
        if(response!=null && response.isSuccessful){
            val contentLength = response.body()?.contentLength()
            response.body()?.close()
            return contentLength?:0
        }
        return 0
    }

    fun pauseDownload(){
        isPaused = true
    }

    fun cancelDownload(){
        isCanceled = true
    }
}